package com.zlcx.tz.live.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.zlcx.tz.live.domain.LiveAgoraAcount;
import com.zlcx.tz.live.exception.BusinessException;
import com.zlcx.tz.live.exception.SendExceptionUtil;
import com.zlcx.tz.live.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.*;

/**
 * <p></p>
 * <PRE>
 * <BR>    修改记录
 * <BR>-----------------------------------------------
 * <BR>    修改日期         修改人          修改内容
 * </PRE>
 *
 * @author zl
 * @version 1.0
 * @date Created in 2019/5/16 11:08
 * @copyright: Copyright (c) founders
 */
@Slf4j
@Service
public class AgoraService {

    @Value("${agora.baseUrl}")
    private String agoraBaseUrl;

    @Autowired
    private RestTemplate restTemplate;

    private static Map<Integer, String> statusMessage = new HashMap<>();

    private static final String agoraStatusValue = "success";

    @Autowired
    private LiveAgoraAcountService agoraAcountService;

    @Resource(name = "msgExecutor")
    AsyncTaskExecutor asyncTaskExecutor;

    @Autowired
    private SendExceptionUtil emailService;

    @Autowired
    SysConfService sysConfService;

    @Autowired
    MessageService messageService;

    static {
        statusMessage.put(200, "请求处理成功");
        statusMessage.put(400, "输入格式错误");
        statusMessage.put(401, "未经授权的（App ID/Customer Certificate匹配错误）");
        statusMessage.put(404, "API 调用错误");
        statusMessage.put(429, "API 调用过于频繁");
        statusMessage.put(500, "服务器内部错误");
    }

    private String getStatusMessage(int status) {
        return statusMessage.get(status);
    }

    private LiveAgoraAcount getCurrentUseAcount() {
        LiveAgoraAcount liveAgoraAcount = agoraAcountService.getCurrentUseAcountCache();
        if (liveAgoraAcount == null) {
            throw new BusinessException("当前没有设置生效的声网账号");
        }
        return liveAgoraAcount;
    }

    private void addAuthHeader(HttpHeaders headers) {
        if (headers == null) {
            headers = new HttpHeaders();
        }
        LiveAgoraAcount liveAgoraAcount = getCurrentUseAcount();
        String auth = liveAgoraAcount.getCustomerId() + ":" + liveAgoraAcount.getCustomerCertificate();
        String authHeader = "Basic " + new String(Base64.encodeBase64(auth.getBytes(Charset.forName("utf-8"))));
        headers.add("Authorization", authHeader);
        headers.setContentType(MediaType.APPLICATION_JSON);
    }


    /**
     * 获取所有项目列表
     *
     * @return
     */
    public List<AgoraProjectVO> getAllProjects() {

        List<AgoraProjectVO> list = Lists.newArrayList();
        String url = agoraBaseUrl + "/projects";
        MultiValueMap paramMap = new LinkedMultiValueMap();
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            log.info("[getAllProjects]获取所有项目列表结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[getAllProjects]获取所有项目列表结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                JSONArray jsonArray = responseObj.getJSONArray("projects");
                if (jsonArray != null && jsonArray.size() > 0) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        AgoraProjectVO projectVO = jsonArray.getObject(i, AgoraProjectVO.class);
                        list.add(projectVO);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[getAllProjects]获取所有项目列表失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[getAllProjects]获取所有项目列表失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

        return list;

    }

    /**
     * 启用/关闭项目AppCertificate
     *
     * @param projectId
     * @param enable
     */
    public void oprateProjectCertificate(String projectId, boolean enable) {
        String url = agoraBaseUrl + "/signkey";
        MultiValueMap paramMap = new LinkedMultiValueMap();
        paramMap.add("id", projectId);
        paramMap.add("enable", enable);

        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.postForEntity(url, httpEntity, String.class, paramMap);
            log.info("[oprateProjectCertificate]启用/关闭项目AppCertificate结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[oprateProjectCertificate]启用/关闭项目AppCertificate失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            }
        } catch (Exception e) {
            log.error("[oprateProjectCertificate]启用/关闭项目AppCertificate失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[oprateProjectCertificate]启用/关闭项目AppCertificate失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

    }


    /**
     * 创建踢人规则
     * <p>
     * 如果 time 字段设置为 0，则表示不封禁，服务端会对频道内符合设定规则的用户进行下线一次的操作。用户可以重新登录进入频道。
     * <p>
     * 踢人规则通过 cname、uid 和 ip 三个字段组合起来过滤实现，规则如下：
     * 如果填写 ip，不填写 cname 或 uid，则该 ip 无法登录 App 中的任何频道
     * 如果填写 cname，不填写 uid 或 ip，则任何人都无法登录 App 中该 cname 对应的频道
     * 如果填写 cname 和 uid，不填写 ip，则该 uid 无法登录 App 中该 cname 对应的频道
     */
    public Long createKickingRule(Long roomId, Long userId, String userIP, int minutes) {
        String url = agoraBaseUrl + "/kicking-rule";
        MultiValueMap paramMap = new LinkedMultiValueMap();
        paramMap.add("appid", getCurrentUseAcount().getAppId());
        if (roomId != null) {
            paramMap.add("cname", roomId.toString());
            // channel name 频道名称，非必填，可以不传，但不能传 cname:""
        }
        if (userId != null) {
            paramMap.add("uid", userId.toString());
            // uid，SDK 可以获取到，非必填，可以不传，但不能传 uid:0
        }
        if (StringUtils.isNotBlank(userIP)) {
            paramMap.add("ip", userIP);
            // IP地址需要封的用户 IP，非必填，可以不传，但不能传 ip:0
        }
        paramMap.add("time", minutes);
        // 封人时间，单位是分钟，最大 1440 分钟，最小一分钟。如果大于 1440 分钟，会被处理成 1440 分钟，如果不传默认为 1 小时。非必填。比如：time:60
        paramMap.add("privileges", Lists.newArrayList("join_channel"));

        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);
        ResponseEntity<String> response;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.postForEntity(url, httpEntity, String.class);
            log.info("[createKickingRule]创建踢人规则结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[createKickingRule]创建踢人规则结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                Long id = responseObj.getLong("id");
                return id;
            }
        } catch (Exception e) {
            log.error("[createKickingRule]创建踢人规则结果失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[createKickingRule]创建踢人规则结果失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

        return null;
    }


    /**
     * 查看踢人规则列表
     */
    public List<AgoraKickingRuleVO> getKickingRuleList() {

        String appid = getCurrentUseAcount().getAppId();
        List<AgoraKickingRuleVO> list = Lists.newArrayList();
        String url = agoraBaseUrl + "/kicking-rule?appid=" + appid;
        MultiValueMap paramMap = new LinkedMultiValueMap();
        paramMap.add("appid", appid);
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            log.info("[getKickingRuleList]查看踢人规则列表结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[getKickingRuleList]查看踢人规则列表结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                JSONArray jsonArray = responseObj.getJSONArray("rules");
                if (jsonArray != null && jsonArray.size() > 0) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        AgoraKickingRuleVO kickingRuleVO = jsonArray.getObject(i, AgoraKickingRuleVO.class);
                        list.add(kickingRuleVO);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[getKickingRuleList]查看踢人规则列表失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[getKickingRuleList]查看踢人规则列表失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

        return list;
    }


    /**
     * 删除规则
     *
     * @param kickingRuleId
     */
    public void deleteKickingRule(Long kickingRuleId) {
        String appID = getCurrentUseAcount().getAppId();
        String url = agoraBaseUrl + "/kicking-rule";
        MultiValueMap paramMap = new LinkedMultiValueMap();
        paramMap.add("appid", appID);
        paramMap.add("id", kickingRuleId);
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap, headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.DELETE, httpEntity, String.class);
            log.info("[deleteKickingRule]删除规则结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[deleteKickingRule]删除规则结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            }
        } catch (Exception e) {
            log.error("[deleteKickingRule]删除规则结果失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[deleteKickingRule]删除规则结果失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

    }


    /**
     * 查询频道内的分角色用户列表
     *
     * @param roomId
     */
    public AgoraChannelRoleListVO getChanelUserList(Long roomId) {
        String appID = getCurrentUseAcount().getAppId();
        String url = agoraBaseUrl + "/channel/user/" + appID + "/" + roomId;
        MultiValueMap paramMap = new LinkedMultiValueMap();
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            log.info("[getChanelUserList]查询频道内的分角色用户列表结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[getChanelUserList]查询频道内的分角色用户列表结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                AgoraChannelRoleListVO agoraChannelRoleListVO = responseObj.getObject("data", AgoraChannelRoleListVO.class);
                return agoraChannelRoleListVO;
            }
        } catch (Exception e) {
            log.error("[getChanelUserList]查询频道内的分角色用户列表失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[getChanelUserList]查询频道内的分角色用户列表失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

        return null;
    }

    /**
     * 查询某个用户在指定频道中的状态
     *
     * @param roomId
     * @param userId
     */
    public AgoraChannelUserStateVO getChanelUserState(Long roomId, Long userId) {
        String appID = getCurrentUseAcount().getAppId();
        String url = agoraBaseUrl + "/channel/user/property/" + appID + "/" + userId + "/" + roomId;
        MultiValueMap paramMap = new LinkedMultiValueMap();
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            log.info("[getChanelUserState]查询某个用户在指定频道中的状态结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[getChanelUserState]查询某个用户在指定频道中的状态失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                AgoraChannelUserStateVO userStateVO = responseObj.getObject("data", AgoraChannelUserStateVO.class);
                return userStateVO;

            }
        } catch (Exception e) {
            log.error("[getChanelUserState]查询某个用户在指定频道中的状态失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[getChanelUserState]查询某个用户在指定频道中的状态失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }
        return null;
    }


    /**
     * 查看获取用量数据
     * 如果不指定项目，将查询该账户下的全部项目
     */
    public List<AgoraProjectUsageVO> getProjectUsageData(Date fromDate, Date toDate, Set<String> projectIds) {

        Assert.notNull(fromDate, "开始时间不能为空");
        Assert.notNull(toDate, "结束时间不能为空");

        List<AgoraProjectUsageVO> list = Lists.newArrayList();

        String url = agoraBaseUrl + "/usage?from_date=" + DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.format(fromDate)
                + "&to_date=" + DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.format(toDate);

        MultiValueMap paramMap = new LinkedMultiValueMap();
        if (CollectionUtils.isNotEmpty(projectIds)) {
            url = url + "&projects=" + Joiner.on(",").join(projectIds);
        }
        HttpHeaders headers = new HttpHeaders();
        addAuthHeader(headers);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(headers);

        ResponseEntity<String> response = null;
        long t0 = System.currentTimeMillis();
        try {
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class, paramMap);
            log.info("[getProjectUsageData]查看获取用量数据结果：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            if (HttpStatus.SC_OK != response.getStatusCodeValue()) {
                log.error("[getProjectUsageData]查看获取用量数据结果失败：cost={}ms,url={},headers={},paramMap={},StatusCode={},StatusMessage={},responseBody={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), response.getStatusCodeValue(), getStatusMessage(response.getStatusCodeValue()), response.getBody());
            } else {
                JSONObject responseObj = JSON.parseObject(response.getBody());
                JSONArray jsonArray = responseObj.getJSONArray("usages");
                if (jsonArray != null && jsonArray.size() > 0) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        AgoraProjectUsageVO projectUsageVO = jsonArray.getObject(i, AgoraProjectUsageVO.class);
                        list.add(projectUsageVO);
                    }
                }

            }
        } catch (Exception e) {
            log.error("[getProjectUsageData]查看获取用量数据失败：cost={}ms,url={},headers={},paramMap={},e={}", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e);
            String msg = String.format("[getProjectUsageData]查看获取用量数据失败：cost=%d ms,url=%s,headers=%s,paramMap=%s,e=%s", System.currentTimeMillis() - t0, url, JSON.toJSONString(headers), JSON.toJSONString(paramMap), e.getMessage());
            emailService.sendException(msg, e);
        }

        return list;
    }

    /**
     * 查询账号当月总用量
     *
     * @return
     */
    public Map<String, Long> getAcountMounthUsage() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        Date fromDate = calendar.getTime();
        Date toDate = new Date();
        Set<String> projects = Sets.newHashSet();
        List<AgoraProjectUsageVO> list = getProjectUsageData(fromDate, toDate, projects);
        Map<String, Long> dataTotal = Maps.newHashMap();
        dataTotal.put("audioTotal", 0L);
        dataTotal.put("sdTotal", 0L);
        dataTotal.put("hdTotal", 0L);
        dataTotal.put("hdpTotal", 0L);
        if (CollectionUtils.isNotEmpty(list)) {
            for (AgoraProjectUsageVO projectUsageVO : list) {
                dataTotal.put("audioTotal", dataTotal.get("audioTotal") + projectUsageVO.getAudioTotalUsage());
                dataTotal.put("sdTotal", dataTotal.get("sdTotal") + projectUsageVO.getSdTotalUsage());
                dataTotal.put("hdTotal", dataTotal.get("hdTotal") + projectUsageVO.getHdTotalUsage());
                dataTotal.put("hdpTotal", dataTotal.get("hdpTotal") + projectUsageVO.getHdpTotalUsage());

            }
        }
        return dataTotal;
    }

    /**
     * 账号用量提醒
     */
    public void alertAcountMounthUsage() {

        asyncTaskExecutor.execute(() -> {
            LiveAgoraAcount liveAgoraAcount = getCurrentUseAcount();
            if (liveAgoraAcount != null) {

                Map<String, Long> datatotal = getAcountMounthUsage();
                Long audioTotal = datatotal.get("audioTotal");
                Long sdTotal = datatotal.get("sdTotal");
                Long hdTotal = datatotal.get("hdTotal");
                Long hdpTotal = datatotal.get("hdpTotal");

                String audioCost = String.valueOf(new BigDecimal(Double.valueOf(audioTotal * 7)).divide(new BigDecimal(Double.valueOf(1000)), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
                String sdCost = String.valueOf(new BigDecimal(Double.valueOf(sdTotal * 28)).divide(new BigDecimal(Double.valueOf(1000)), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
                String hdCost = String.valueOf(new BigDecimal(Double.valueOf(hdTotal * 105)).divide(new BigDecimal(Double.valueOf(1000)), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
                String hdpCost = String.valueOf(new BigDecimal(Double.valueOf(hdpTotal * 105)).divide(new BigDecimal(Double.valueOf(1000)), 2, BigDecimal.ROUND_HALF_UP).doubleValue());

                StringBuilder emsMsg = new StringBuilder();
                emsMsg.append("声网账号使用量提醒：[").append(sysConfService.getSysEnv()).append("]环境APP ID[").append(liveAgoraAcount.getAppId())
                        .append("]本月语音时长").append(audioTotal).append("分钟预计").append(audioCost)
                        .append("元，标清时长").append(sdTotal).append("分钟预计").append(sdCost)
                        .append("元，高清时长").append(hdTotal).append("分钟预计").append(hdCost)
                        .append("元，超高清时长").append(hdpTotal).append("分钟预计").append(hdpCost)
                        .append("元，实际以声网扣除赠送一万分钟之后的价格为准！");

                messageService.sendEmsMsg(sysConfService.getComplainPhones(), emsMsg.toString(), null);
            }
        });
    }


}
